package conf

import (
	"bufio"
	"bytes"
	"fmt"
	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/axgle/mahonia"
	"github.com/mitchellh/mapstructure"
	"github.com/spf13/viper"
	"gopkg.in/yaml.v2"
	"io"
	"os"
	"path/filepath"
	"strings"
)

// ============================================================================

// ============================================================================

type D struct {
	*viper.Viper
	Ver int32
	Safe
	Sep string
}
func NewConf()(ret *D) {
	Sep:="."
	ret=&D{Viper: viper.NewWithOptions(viper.KeyDelimiter(Sep))}
	ret.Sep=Sep
	return
}
func (self *D)ToString(key... interface{})(ret string) {
	return ToString(self.Get(self.Link(key...)))
}

func (self *D)GetMap(key... interface{})(ret map[string]bool) {
	ret = map[string]bool{}
	for k, _ := range self.GetStringMap(self.Link(key...)) {
		ret[k]=true
	}
	return
}
func  (self *D)Link(args ...interface{}) (ret string) {
	return strings.Join(ToStringSlice(args), self.Sep)
}
func (self *D) All()(ret map[string]interface{}) {
	return self.AllSettings()
}
func (self *D) ToYamlString()string {
	c := self.AllSettings()
	b, _ := yaml.Marshal(c)
	return string(b)
}
func LoadYamlString(d string)(config *D)  {
	config = NewConf()
	r := bytes.NewReader([]byte(d))
	config.SetConfigType("yaml")
	config.ReadConfig(r)
	return
}
func LoadFile(fpath, filename, Type string) (config *D) {
	config = NewConf()
	switch Type {
	case "xlsx":
		if filename==""{
			var files []string
			err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
				files = append(files, path)
				return nil
			})
			if err != nil {
				panic(err)
			}
			for _, file := range files {
				println(file)
				config.Loadxlsx(file)
			}
			return
		}
	default:
		config.AddConfigPath(fpath)
		config.SetConfigName(filename)
		config.SetConfigType(Type)
		if err := config.ReadInConfig(); err != nil {
			return nil
		}
	}
	return
}

func LoadStruct(name string,d interface{})(config *D)  {
	config = NewConf()
	config.SaveData(d,name)
	return
}
func (self *D)SaveData(d interface{},name ...interface{}) {
	//d=struct 不能sub
	l:=self.GetSafe(name...)
	l.Lock()
	defer l.Unlock()
	var m map[string]interface{}
	mapstructure.Decode(d, &m)
	switch m  {
	case nil:
		self.Set(self.Link(name...),d)
	default:
		self.Set(self.Link(name...),m)
	}
}

func (self *D) Loadxlsx(file string) {
		f, err := excelize.OpenFile(file)
		if err != nil {
			return
		}
		// 获取 Sheet1 上所有单元格
		for key, _ := range f.GetComments() {
			rows := f.GetRows(key)
			t:=strings.Split(key,"|")
			if len(t)!=2{
				continue
			}
			title:=rows[1]
			for _, value := range rows[4:] {
				for key, value2 := range value {
					if title[key]!=""{
						self.SaveData(value2,t[1],value[0],title[key])
					}
				}

			}
		}

	return
}
func WriteYamlFile(path, filename string, cur interface{}) {
	new := &Api_yaml{}
	new.Write(path+filename+".yaml", cur)
}
func ReadYamlFile(fpath, filename string, cur interface{}) {
	config := LoadFile(fpath, filename, "yaml")
	if config == nil {
		return
	}
	if err := config.Unmarshal(&cur); err != nil {
		fmt.Println(err)
	}
}
//GetCurDir 获取当前文件执行的路径
func GetCurDir() string {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return ""
	}
	return strings.Replace(dir, "\\", "/", -1)
}
func ReadFile(path, gbk, sep string, f func([]string)) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()
	bufReader := bufio.NewReader(file)
	decoder := mahonia.NewDecoder(gbk) // 把原来ANSI格式的文本文件里的字符，用gbk进行解码。
	for {
		line, _, err := bufReader.ReadLine() // 按行读
		if err != nil {
			if err == io.EOF {
				err = nil
				break
			}
		} else {
			ret := decoder.ConvertString(string(line))
			tmp := strings.Split(ret, sep)
			if len(tmp) != 0 {
				f(tmp)
			}
		}
	}

}
func IsDirExists(path string) bool {
	fi, err := os.Stat(path)
	if err != nil {
		return os.IsExist(err)
	} else {
		return fi.IsDir()
	}

}

func IsFileExists(file string) bool {
	_, err := os.Stat(file)
	return err == nil || os.IsExist(err)
}
